package com.digua.base.socket

import android.Manifest
import android.content.Context
import android.content.IntentFilter
import android.net.ConnectivityManager
import com.blankj.utilcode.util.NetworkUtils.NetworkChangedReceiver
import com.digua.base.socket.dispatcher.AppResponseDispatcher
import com.digua.base.socket.dispatcher.ResponseProcessEngine
import com.digua.base.util.LogUtil
import com.digua.base.util.PerUtil
import java.util.Objects

/**
 * 参考：https://github.com/0xZhangKe/WebSocketDemo/tree/master
 */
class WebSocketHandler {

    companion object {
        //消息发送引擎
        private var webSocketEngine: WebSocketEngine? = null

        //消息处理引擎
        private var responseProcessEngine: ResponseProcessEngine? = null

        //默认的 WebSocket 链接
        private var defaultWebSocket: WebSocketManager? = null

        //对 [.mWebSocketMap] 操作时的锁
        private val WS_MAP_BLOCK: Any = HashMap<Any, Any>()

        //通过 Map 存储 WSM 对象，以此支持多个链接
        private var mWebSocketMap: MutableMap<String, WebSocketManager>? = null

        /**
         * 初始化默认的 WebSocket 链接
         *
         * @param setting 该链接的相关设置参数
         */
        private fun init(setting: WebSocketSetting?): WebSocketManager {
            if (defaultWebSocket == null) {
                synchronized(WebSocketHandler::class.java) {
                    if (webSocketEngine == null) {
                        webSocketEngine = WebSocketEngine()
                    }
                    if (responseProcessEngine == null) {
                        responseProcessEngine = ResponseProcessEngine()
                    }
                    if (defaultWebSocket == null) {
                        defaultWebSocket = WebSocketManager(setting, webSocketEngine, responseProcessEngine)
                    }
                }
            } else {
                LogUtil.e("Default WebSocketManager exists!do not start again!")
            }
            return defaultWebSocket!!
        }

        /**
         * 初始化默认的 WebSocket 链接
         *
         * @param setting 该链接的相关设置参数
         */
        fun <T> initDef(socketUrl: String, beanClz: Class<T>): WebSocketManager {
            val manager = getDefault()
            val connectUrl = manager?.setting?.connectUrl
            if (manager != null) {
                if (Objects.equals(connectUrl, socketUrl)) {
                    return manager.reconnect()
                } else {
                    manager.disConnect()
                    manager.destroy()
                }
            }
            val setting = WebSocketSetting()
            //链接地址，必填，例如 wss://localhost:8080
            setting.connectUrl = socketUrl
            //设置链接超时时间
            setting.connectTimeout = 10 * 1000
            //设置心跳间隔时间
            setting.connectionLostTimeout = 60
            //设置断开后的重连次数，可以设置的很大，不会有什么性能上的影响
            setting.reconnectFrequency = 40
            //设置 Headers
            //setting.httpHeaders = header
            //设置消息分发器，接收到数据后先进入该类中处理，处理完再发送到下游
            setting.responseProcessDispatcher = AppResponseDispatcher(beanClz)
            //接收到数据后是否放入子线程处理，只有设置了 ResponseProcessDispatcher 才有意义
            setting.processDataOnBackground = true
            //网络状态发生变化后是否重连，
            //需要调用 WebSocketHandler.registerNetworkChangedReceiver(context) 方法注册网络监听广播
            setting.reconnectWithNetworkChanged = true
            //通过 init 方法初始化默认的 WebSocketManager 对象
            return init(setting)
        }

        /**
         * 通过唯一标识符新建一个 WebSocket 链接
         *
         * @param key     该 WebSocketManager 的唯一标识符，
         * 后面需要通过这个 key 来获取到对应的 WebSocketManager
         * @param setting 该链接的相关设置参数
         */
        fun initGeneralWebSocket(key: String, setting: WebSocketSetting?): WebSocketManager? {
            checkEngineNullAndInit()
            checkWebSocketMapNullAndInit()
            synchronized(WS_MAP_BLOCK) {
                return mWebSocketMap?.let {
                    if (it.containsKey(key)) {
                        LogUtil.e("WebSocketManager exists!do not start again!")
                        it[key]
                    } else {
                        val wsm = WebSocketManager(setting, webSocketEngine, responseProcessEngine)
                        it[key] = wsm
                        wsm
                    }
                }
            }
        }

        /**
         * 获取默认的 WebSocket 链接，
         * 调用此方法之前需要先调用 [.init] 方法初始化
         *
         * @return 返回一个 [WebSocketManager] 实例
         */
        fun getDefault(): WebSocketManager? {
            return defaultWebSocket
        }

        /**
         * 获取 WebSocketManager 对象
         *
         * @param key 该 WebSocketManager 的 key
         * @return 可能为空，代表该 WebSocketManager 对象不存在或已移除
         */
        fun getWebSocket(key: String): WebSocketManager? {
            checkWebSocketMapNullAndInit()
            return if (mWebSocketMap!!.containsKey(key)) {
                mWebSocketMap!![key]
            } else {
                null
            }
        }

        /**
         * 获取所有 WebSocketManager（defaultWebSocketManager 除外）
         */
        fun getAllWebSocket(): Map<String, WebSocketManager>? {
            checkWebSocketMapNullAndInit()
            return mWebSocketMap
        }

        /**
         * 移除一个 WebSocketManager 对象
         *
         * @param key 该 WebSocketManager 的 key
         * @return 返回移除的 WebSocketManager，可能为空
         */
        fun removeWebSocket(key: String): WebSocketManager? {
            checkWebSocketMapNullAndInit()
            return if (mWebSocketMap!!.containsKey(key)) {
                val removed = mWebSocketMap!![key]
                synchronized(WS_MAP_BLOCK) { mWebSocketMap!!.remove(key) }
                removed
            } else {
                null
            }
        }

        /**
         * 注册网络变化监听广播，网络由不可用变为可用时会重新链接 WebSocket
         *
         * @param context 此处应该使用 ApplicationContext，避免内存泄漏以及其它异常。
         */
        fun registerNetworkChangedReceiver(context: Context) {
            PerUtil.permission(null, "网络监听广播注册失败", {
                try {
                    val filter = IntentFilter()
                    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
                    context.registerReceiver(NetworkChangedReceiver(), filter)
                } catch (e: Exception) {
                    LogUtil.e("网络监听广播注册失败：", e)
                }
            }, Manifest.permission.ACCESS_NETWORK_STATE)
        }

        /**
         * 初始化引擎
         */
        private fun checkEngineNullAndInit() {
            if (webSocketEngine == null || responseProcessEngine == null) {
                synchronized(WebSocketHandler::class.java) {
                    if (webSocketEngine == null) {
                        webSocketEngine = WebSocketEngine()
                    }
                    if (responseProcessEngine == null) {
                        responseProcessEngine = ResponseProcessEngine()
                    }
                }
            }
        }

        /**
         * 初始化 mWebSocketMap
         */
        private fun checkWebSocketMapNullAndInit() {
            if (mWebSocketMap == null) {
                synchronized(WS_MAP_BLOCK) {
                    if (mWebSocketMap == null) {
                        mWebSocketMap = HashMap()
                    }
                }
            }
        }

    }
}